//Copyright (c) Microsoft Corporation. All rights reserved.
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Runtime.InteropServices;
using System.Xml.Linq;

using Microsoft.Office.OneNote.Interop;

namespace Microsoft.Office.OneNote
{
	public sealed partial class OneNoteApplication
	{
        private readonly IOneNoteApplication _ptr;

		private OneNoteApplication()
		{
			try
			{
                _ptr = (IOneNoteApplication)(new OneNoteApplicationClass());
			}
			catch (COMException exc)
			{
				if (exc.ErrorCode == NativeErrorCodes.REGDB_E_CLASSNOTREG)
				{
					throw new OneNoteException(Exceptions.Messages._OneNoteNotInstalled, exc);
				}

				throw;
			}
			catch (FileNotFoundException exc)
			{
                throw new OneNoteException(Exceptions.Messages._OneNoteNotInstalled, exc);
			}
		}

		public XDocument GetHierarchy(OneNoteObjectId startNodeId, HierarchyScope scope)
		{
            string xml;

            VerifySuccess(_ptr.GetHierarchy(startNodeId.ToString(), scope, out xml));

            return XDocument.Parse(xml);
        }

        public void UpdateHierarchy(XDocument changesXml)
		{
            VerifySuccess(_ptr.UpdateHierarchy(changesXml.ToString()));
		}

        public OneNoteObjectId OpenHierarchy(String path, OneNoteObjectId relativeTo, CreateHierarchyType ifNotExist)
		{
            string objectId;

            VerifySuccess(_ptr.OpenHierarchy(path, relativeTo.ToString(), out objectId, ifNotExist));

            return OneNoteObjectId.Parse(objectId);
		}

        public OneNoteObjectId OpenHierarchy(String path, OneNoteObjectId relativeTo)
		{
            return OpenHierarchy(path, relativeTo, CreateHierarchyType.None);
		}

        public void DeleteHierarchy(OneNoteObjectId objectId, DateTime expectedLastModified)
		{
            VerifySuccess(_ptr.DeleteHierarchy(objectId.ToString(), expectedLastModified));
        }

        public void DeleteHierarchy(OneNoteObjectId objectId)
		{
            DeleteHierarchy(objectId, DateTime.MinValue);
		}

        public OneNoteObjectId CreateNewPage(OneNoteObjectId sectionId, NewPageStyle newPageStyle)
		{
            string pageId;

            VerifySuccess(_ptr.CreateNewPage(sectionId.ToString(), out pageId, newPageStyle));

            return OneNoteObjectId.Parse(pageId);
        }

        public OneNoteObjectId CreateNewPage(OneNoteObjectId sectionId)
		{
            return CreateNewPage(sectionId, NewPageStyle.Default);
		}

        public void CloseNotebook(OneNoteObjectId notebookId)
		{
            VerifySuccess(_ptr.CloseNotebook(notebookId.ToString()));
        }

        public OneNoteObjectId GetParent(OneNoteObjectId objectId)
        {
            string parentId;

            VerifySuccess(_ptr.GetHierarchyParent(objectId.ToString(), out parentId));

            return OneNoteObjectId.Parse(parentId);
        }

		// Page content level operations
        public XDocument GetPageContent(OneNoteObjectId pageId, PageInfo pageInfoToExport)
		{
            string pageXml;

            VerifySuccess(_ptr.GetPageContent(pageId.ToString(), out pageXml, pageInfoToExport));

            return XDocument.Parse(pageXml);
		}

        public XDocument GetPageContent(OneNoteObjectId pageId)
		{
            return GetPageContent(pageId, PageInfo.Basic);
		}

        public void UpdatePageContent(XDocument pageChanges, DateTime expectedLastModified)
		{
            VerifySuccess(_ptr.UpdatePageContent(pageChanges.ToString(), expectedLastModified));
		}

        public void UpdatePageContent(XDocument pageChanges)
		{
            UpdatePageContent(pageChanges, DateTime.MinValue);
		}

        public byte[] GetBinaryPageContent(OneNoteObjectId pageId, OneNoteObjectId callbackId)
		{
            string base64;

			VerifySuccess(_ptr.GetBinaryPageContent(pageId.ToString(), callbackId.ToString(), out base64));

            return Convert.FromBase64String(base64);
		}

        public void DeletePageContent(OneNoteObjectId pageId, OneNoteObjectId objectId, DateTime expectedLastModified)
        {
            VerifySuccess(_ptr.DeletePageContent(pageId.ToString(), objectId.ToString(), expectedLastModified));
		}

        public void DeletePageContent(OneNoteObjectId pageId, OneNoteObjectId objectId)
		{
            DeletePageContent(pageId, objectId, DateTime.MinValue);
        }

		// Actions
        public void NavigateTo(OneNoteObjectId pageId, OneNoteObjectId objectId, bool newWindow)
		{
            VerifySuccess(_ptr.NavigateTo(pageId.ToString(), objectId.ToString(), newWindow));
		}

        public void NavigateTo(OneNoteObjectId pageId, OneNoteObjectId objectId)
		{
            NavigateTo(pageId, objectId, false);
		}

        public void NavigateTo(OneNoteObjectId hierarchyId, bool newWindow)
        {
            NavigateTo(hierarchyId, OneNoteObjectId.Empty, newWindow);
        }

        public void NavigateTo(OneNoteObjectId hierarchyId)
        {
            NavigateTo(hierarchyId, false);
        }

        public void Publish(OneNoteObjectId hierarchyId, String targetFilePath, PublishFormat format, Guid exporterClsid)
		{
            string clsid = "0";

            if (exporterClsid != Guid.Empty)
            {
                clsid = exporterClsid.ToString();
            }

            VerifySuccess(_ptr.Publish(hierarchyId.ToString(), targetFilePath, format, clsid));
		}

        public void Publish(OneNoteObjectId hierarchyId, String targetFilePath, PublishFormat format)
        {
            Publish(hierarchyId, targetFilePath, format, Guid.Empty);
        }

        public void Publish(OneNoteObjectId hierarchyId, String targetFilePath)
		{
            Publish(hierarchyId, targetFilePath, PublishFormat.OneNote);
		}

        public String OpenPackage(String packagePath, String destinationPath)
		{
            string path;

            VerifySuccess(_ptr.OpenPackage(packagePath, destinationPath, out path));

            return path;
		}

        public Uri GetHyperlinkToObject(OneNoteObjectId hierarchyId, OneNoteObjectId pageContentObjectId)
		{
            string hyperlink;

            VerifySuccess(_ptr.GetHyperlinkToObject(hierarchyId.ToString(), pageContentObjectId.ToString(), out hyperlink));

            return new Uri(hyperlink);
		}

        [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Unindexed")]
        public XDocument FindPages(OneNoteObjectId objectId, String searchTerms, bool display, bool includeUnindexedPages)
		{
            string xml;

            VerifySuccess(_ptr.FindPages(objectId.ToString(), searchTerms, out xml, includeUnindexedPages, display));

            return XDocument.Parse(xml);
		}

        public XDocument FindPages(OneNoteObjectId objectId, String searchTerms, bool display)
        {
            return FindPages(objectId, searchTerms, display, false);
        }

        public XDocument FindPages(OneNoteObjectId objectId, String searchTerms)
        {
            return FindPages(objectId, searchTerms, false);
        }

        public string GetSpecialLocation(SpecialLocation specialLocation)
		{
            string specialLocationPath;

            VerifySuccess(_ptr.GetSpecialLocation(specialLocation, out specialLocationPath));
            
            return specialLocationPath;
		}

        private static void VerifySuccess(int errorCode)
        {
            if (errorCode < 0)
            {
                throw OneNoteException.GetExceptionForHR(errorCode);
            }
        }
	}
}